/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import { AbstractInvokeExpr, Stmt, ArkMethod, ArkFile, ArkAssignStmt, ArkStaticInvokeExpr, ArkClass } from "arkanalyzer/lib";
import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { BaseChecker, BaseMetaData } from "../BaseChecker";
import { Defects, IssueReport } from "../../model/Defects";
import { ClassMatcher, FileMatcher, MatcherCallback, MatcherTypes, MethodMatcher } from "../../matcher/Matchers";
import { CheckerUtils } from "../../utils/checker/CheckerUtils";
import { Rule } from "../../model/Rule";
import { RuleListUtil } from "../../utils/common/DefectsList";

type valueType = {
    name: string,
    ref: string,
    usedStmts: ArkAssignStmt[]
};
type RightOp = {
    yieldValue: ArkStaticInvokeExpr
};
interface lineColumnInfo {
    line: number,
    startCol: number,
    endCol: number,
    filePath: string
};
const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'RequireAwaitCheck');
const gmetaData: BaseMetaData = {
    severity: 2,
    ruleDocPath: "docs/require-await-check.md", // TODO: support url
    description: "Disallow async functions which have no `await` expression."
};
export class RequireAwaitCheck implements BaseChecker {
    readonly metaData: BaseMetaData = gmetaData;
    public rule: Rule;
    public defects: Defects[] = [];
    public issues: IssueReport[] = [];
    private fileMatcher: FileMatcher = {
        matcherType: MatcherTypes.FILE,
    };

    private classMatcher: ClassMatcher = {
        file: [this.fileMatcher],
        matcherType: MatcherTypes.CLASS
    };
    private methodMatcher: MethodMatcher = {
        matcherType: MatcherTypes.METHOD,
        class: [this.classMatcher]
    };
    public registerMatchers(): MatcherCallback[] {
        const matchMethod: MatcherCallback = {
            matcher: this.methodMatcher,
            callback: this.check
        }
        return [matchMethod];
    }
    /**
     * 判断字符串中是否包含await关键字
     *
     * @param text 要判断的字符串
     * @returns 如果字符串中包含await关键字，则返回true；否则返回false
     */
    private containsAwaitKeyword(text: string): boolean {
        return /await\b/.test(text);
    }
    /**
     * 判断给定的文本中是否包含异步关键字 'async'
     *
     * @param text 待检查的文本
     * @returns 如果文本中包含 'async' 关键字，则返回 true，否则返回 false
     */
    private containsAsyncKeyword(text: string): boolean {
        return /async\b/.test(text);
    }
    /**
     * 检查文本中是否包含 "catch" 关键字
     *
     * @param text 需要检查的文本
     * @returns 如果文本中包含 "catch" 关键字，则返回 true，否则返回 false
     */
    private containsCatchKeyword(text: string): boolean {
        return /catch\b/.test(text);
    }
    /**
     * 判断字符串中是否包含 'then' 关键字
     *
     * @param text 要检查的字符串
     * @returns 如果字符串中包含 'then' 关键字，则返回 true；否则返回 false
     */
    private containsThenKeyword(text: string): boolean {
        return /then\b/.test(text);
    }
    /**
     * 判断字符串中是否包含关键词 "resolve"
     *
     * @param text 待判断的字符串
     * @returns 如果字符串中包含关键词 "resolve"，则返回 true，否则返回 false
     */
    private containsResolveKeyword(text: string): boolean {
        return /resolve\b/.test(text);
    }
    /**
     * 检查字符串中是否包含拒绝关键字
     *
     * @param text 待检查的字符串
     * @returns 如果包含拒绝关键字则返回 true，否则返回 false
     */
    private containsRejectKeyword(text: string): boolean {
        return /reject\b/.test(text);
    }
    /**
     * 检查字符串中是否包含 "Promise" 关键字
     *
     * @param text 要检查的字符串
     * @returns 如果字符串中包含 "Promise" 关键字，则返回 true；否则返回 false
     */
    private containsPromiseKeyword(text: string): boolean {
        return /Promise\b/.test(text);
    }
    /**
     * 判断给定的字符串中是否包含"unknown" 关键字
     *
     * @param text 要检查的字符串
     * @returns 如果包含未知的关键词，则返回 true；否则返回 false
     */
    private containsUnknownKeyword(text: string): boolean {
        return /unknown\b/.test(text);
    }
    /**
     * 判断字符串中是否包含 'void' 关键字
     *
     * @param text 要检查的字符串
     * @returns 如果包含 'void' 关键字，则返回 true；否则返回 false
     */
    private containsVoidKeyword(text: string): boolean {
        return /void\b/.test(text);
    }
    public check = (method: ArkMethod) => {
        // 获取方法体的语句列表
        const stmts = method.getBody()?.getCfg().getStmts() ?? [];
        // 获取方法的代码
        const code = method.getCode() ?? '';
        // 获取方法所属的类
        let declareClass = method.getDeclaringArkClass();
        // 获取类所属的文件
        const arkFile = declareClass.getDeclaringArkFile();
        // 初始化异步文本变量
        let asyncText = '';
        // 检查函数体是否为空或者是否包含过多的语句，如果是则直接返回
        if (stmts.length === 0 || stmts.length >= 10) {
            return;
        }
        this.check1(code, stmts, asyncText, method, arkFile, declareClass);
    }
    private check1(code: string, stmts: Stmt[], asyncText: string, method: ArkMethod,
        arkFile: ArkFile, declareClass: ArkClass): void {
        if (!this.containsAsyncKeyword(code)) {
            return;
        }
        this.check11(code, stmts, asyncText, method, arkFile, declareClass);
    }
    private check11(code: string, stmts: Stmt[], asyncText: string, method: ArkMethod,
        arkFile: ArkFile, declareClass: ArkClass): void {
        for (const stmt of stmts) {
            // 从语句中获取调用表达式
            const invokeExpr = CheckerUtils.getInvokeExprFromStmt(stmt);
            const text = stmt.getOriginalText() ?? '';
            if (!text) {
                continue;
            }
            if (!invokeExpr) {
                this.nonInvokeExprCheck(code, asyncText, method, arkFile, stmt, declareClass);
                continue;
            }
            this.hasInvokeExprCheck(code, stmt, method, arkFile, asyncText, invokeExpr);
        }
    }
    private nonInvokeExprCheck(code: string, asyncText: string, method: ArkMethod, arkFile: ArkFile,
        stmt: Stmt, declareClass: ArkClass): void {
        if (this.containsAsyncKeyword(code)) {
            asyncText = code;
        }
        if (asyncText) {
            // 如果代码中包含async关键字，则记录异步文本
            if (this.containsAsyncKeyword(code)) {
                asyncText = code;
            }
        }
        // 如果存在异步文本，则进行正则匹配
        this.nonInvokeExprCheck1(code, asyncText, method, arkFile, stmt, declareClass);
    }
    private nonInvokeExprCheck1(code: string, asyncText: string, method: ArkMethod, arkFile: ArkFile,
        stmt: Stmt, declareClass: ArkClass): void {
        if (asyncText) {
            const regex = /\basync\s+([^(]+)/g;
            const regex1 = /async\s*\(\)(?::\s*.*?)?\s*=>/;
            const match1 = asyncText.match(regex1);
            const match = asyncText.match(regex);
            const methodName = method.getName();
            if (match) {
                this.matchCheckAll(match, stmt, methodName, arkFile, declareClass, method);
            }
            if (match1) {
                this.match1Check(match1, stmt, arkFile);
            }
        }
    }
    private hasInvokeExprCheck(code: string, stmt: Stmt, method: ArkMethod, arkFile: ArkFile,
        asyncText: string, invokeExpr: AbstractInvokeExpr): void {
        if (this.containsAsyncKeyword(code)) {
            asyncText = code;
        }
        if (asyncText) {
            this.asyncTextCheck1(asyncText, invokeExpr, stmt, arkFile, method);
            this.asyncTextCheck2(asyncText, invokeExpr, stmt, arkFile, method);
        }
    }
    private matchCheckAll(match: RegExpMatchArray, stmt: Stmt, methodName: string, arkFile: ArkFile,
        declareClass: ArkClass, method: ArkMethod): void {
        const asyncFunction = match[0];
        let text = stmt.getOriginalText() ?? '';
        this.matchCheckAll1(text, asyncFunction, methodName, arkFile, method);
        this.matchCheckAll2(asyncFunction, methodName, arkFile, method);
        this.matchCheckAll3(asyncFunction, methodName, arkFile, declareClass);
    }
    private matchCheckAll1(text: string, asyncFunction: string, methodName: string, arkFile: ArkFile, method: ArkMethod): void {
        if (text && !this.containsAwaitKeyword(text) && !this.containsCatchKeyword(text) && !
            this.containsThenKeyword(text)) {
            this.matchCheckAll12(text, asyncFunction, methodName, arkFile, method);
        }
    }
    private matchCheckAll12(text: string, asyncFunction: string, methodName: string, arkFile: ArkFile, method: ArkMethod): void {
        if (!this.containsRejectKeyword(text) && !this.containsResolveKeyword(text)) {
            this.matchCheck1(text, asyncFunction, methodName, arkFile);
            this.matchCheckAll11(text, asyncFunction, methodName, arkFile, method);
        }
    }
    private matchCheckAll11(text: string, asyncFunction: string, methodName: string, arkFile: ArkFile, method: ArkMethod): void {
        if (!text.includes('return ') || text.includes('await ')) {
            const stmts = method.getBody()?.getCfg().getStmts() ?? [];
            let flag = { value: true };
            this.matchCheck2(stmts, flag);
            this.matchCheck3(method, flag);
            this.matchCheck4(method, flag, text);
            if (text.includes('Omit')) {
                flag.value = false;
            }
            this.matchCheck5(stmts, flag, text);
            if (flag.value === true) {
                this.metaData.description = `Async function ${methodName} has no 'await' expression.`;
                this.addIssueReport(arkFile, asyncFunction, this.metaData);
            }
        }
    }
    private matchCheckAll2(asyncFunction: string, methodName: string, arkFile: ArkFile, method: ArkMethod): void {
        const locals = method.getBody()?.getLocals() ?? [];
        for (const [key, value] of locals.entries()) {
            const keyName = key?.toString() ?? '';
            if (keyName === 'this') {
                continue;
            }
            const usedStmts = value.getUsedStmts() ?? [];
            if (usedStmts.length > 0) {
                const valueName = value.getName();
                this.matchCheckAll21(valueName, methodName, arkFile, usedStmts, asyncFunction);
            }
        }
    }
    private matchCheckAll21(valueName: string, methodName: string, arkFile: ArkFile, usedStmts: Stmt[],
        asyncFunction: string): void {
        if (valueName.includes(methodName)) {
            for (const usedStmt of usedStmts) {
                const text = usedStmt.getOriginalText() ?? '';
                this.matchCheckAll211(text, asyncFunction, arkFile, methodName);
            }
        }
    }
    private matchCheckAll211(text: string, asyncFunction: string, arkFile: ArkFile, methodName: string): void {
        if (!text.startsWith('await')) {
            this.metaData.description = `Async function ${methodName} has no 'await' expression.`;
            this.addIssueReport(arkFile, asyncFunction, this.metaData);
        } else {
            const regex = /await\s*\(\s*async\s*\(\)(?::\s*.*?)?\s*=>/;
            const match = text.match(regex);
            if (match) {
                const target = match[0];
                this.metaData.description = "Async arrow function has no 'await' expression.";
                this.addIssueReport(arkFile, target, this.metaData);
            }
        }
    }
    private matchCheckAll3(asyncFunction: string, methodName: string, arkFile: ArkFile, declareClass: ArkClass): void {
        const methods = declareClass.getMethods();
        if (methods.length > 2) {
            for (const method of methods) {
                const methodCode = method.getCode();
                if (!methodCode) {
                    continue;
                }
                const MethodName = method.getSignature()?.getMethodSubSignature()?.getMethodName() ?? '';
                this.matchCheckAll31(asyncFunction, methodName, MethodName, arkFile, methodCode);
            }
        }
    }
    private matchCheckAll31(asyncFunction: string, methodName: string, MethodName: string, arkFile: ArkFile, methodCode: string): void {
        if (MethodName.includes('%') && MethodName.includes(methodName)) {
            if (!methodCode.startsWith('await')) {
                const regex = /async\s*\(\)(?::\s*.*?)?\s*=>/;
                const match = methodCode.match(regex);
                if (match) {
                    const target = match[0];
                    this.metaData.description = "Async arrow function has no 'await' expression.";
                    this.addIssueReport(arkFile, target, this.metaData);
                } else {
                    this.metaData.description = `Async function ${methodName} has no 'await' expression.`;
                    this.addIssueReport(arkFile, asyncFunction, this.metaData);
                }
            }
        }
    }
    private matchCheck1(text: string, asyncFunction: string, methodName: string, arkFile: ArkFile): void {
        const regex = /return\s+\w+\(.*?\)/;
        if (regex.test(text.trim())) {
            return;
        }
        this.matchCheck11(text, asyncFunction, methodName, arkFile);
    }
    private matchCheck11(text: string, asyncFunction: string, methodName: string, arkFile: ArkFile): void {
        if (text.includes('return ')) {
            if (text.includes('Promise')) {
                return;
            }
            this.metaData.description = `Async function ${methodName} has no 'await' expression.`;
            this.addIssueReport(arkFile, asyncFunction, this.metaData);
        }
    }
    private matchCheck2(stmts: Stmt[], flag: { value: boolean }): void {
        for (const stmt of stmts) {
            const text = stmt.getOriginalText() ?? '';
            if (this.containsAwaitKeyword(text)) {
                flag.value = false;
            }
        }
    }
    private matchCheck3(method: ArkMethod, flag: { value: boolean }): void {
        const usedGlobals = method.getBody()?.getUsedGlobals() ?? [];
        for (const [key, value] of usedGlobals?.entries()) {
            const Value = value as unknown as valueType;
            const usedStmts = Value?.usedStmts ?? [];
            for (const usedStmt of usedStmts) {
                if (usedStmt instanceof ArkAssignStmt) {
                    const rightOp = usedStmt.getRightOp() as unknown as RightOp;
                    const methodName = rightOp?.yieldValue?.getMethodSignature()?.getMethodSubSignature()?.getMethodName() ?? '';
                    if (methodName !== '') {
                        flag.value = false;
                    }
                }
            }
        }
    }
    private matchCheck4(method: ArkMethod, flag: { value: boolean }, text: string): void {
        const parameters = method.getSignature()?.getMethodSubSignature()?.getParameters() ?? [];
        for (const parameter of parameters) {
            const parameterName = parameter.getName();
            if (text.includes(parameterName)) {
                flag.value = false;
            }
        }
    }
    private matchCheck5(stmts: Stmt[], flag: { value: boolean }, text: string): void {
        for (const stmt of stmts) {
            if (stmt instanceof ArkAssignStmt) {
                const leftOp = stmt.getLeftOp()?.toString() ?? '';
                if (this.matchCheck51(leftOp, flag, text)) {
                    continue;
                }
            }
        }
    }
    private matchCheck51(leftOp: string, flag: { value: boolean }, text: string): boolean {
        if (leftOp === 'this' || leftOp.startsWith('%')) {
            return true;
        }
        this.matchCheck511(leftOp, flag, text);
        return false;
    }
    private matchCheck511(leftOp: string, flag: { value: boolean }, text: string): void {
        if (text.includes(leftOp)) {
            flag.value = false;
        }
    }
    private match1Check(match1: RegExpMatchArray, stmt: Stmt, arkFile: ArkFile): void {
        const asyncFunction = match1.input ?? '';
        let text = stmt.getOriginalText() ?? '';
        // 如果语句文本存在且不包含await关键字
        if (text && !this.containsAwaitKeyword(text)) {
            // 如果语句文本不包含catch、then、reject、resolve关键字
            if (!this.containsCatchKeyword(text) && !this.containsThenKeyword(text)) {
                // 如果语句文本不包含reject,resolve关键字
                this.match1Check1(text, asyncFunction, arkFile);
            }
        }
    }
    private match1Check1(text: string, asyncFunction: string, arkFile: ArkFile): void {
        if (!this.containsRejectKeyword(text) && !this.containsResolveKeyword(text)) {
            this.metaData.description = "Async arrow function has no 'await' expression.";
            if (asyncFunction) {
                this.addIssueReport(arkFile, asyncFunction, this.metaData);
            }
        }
    }
    private asyncTextCheck1(asyncText: string, invokeExpr: AbstractInvokeExpr, stmt: Stmt,
        arkFile: ArkFile, method: ArkMethod): void {
        const regex = /\basync\s+([^(]+)/g;
        const match = asyncText.match(regex);
        const regex1 = /async\s*\(.*?\)(?::\s*.*?)?\s*=>/;
        const match1 = asyncText.match(regex1);
        const methodName = method.getName();
        if (match) {
            this.asyncTextCheck13(match, invokeExpr, stmt, arkFile, method, methodName);
        }
        if (match1) {
            this.asyncTextCheck13(match1, invokeExpr, stmt, arkFile, method, methodName);
        }
    }
    private asyncTextCheck13(match: RegExpMatchArray, invokeExpr: AbstractInvokeExpr, stmt: Stmt,
        arkFile: ArkFile, method: ArkMethod, methodName: string): void {
        const asyncFunction = match[0];
        // 获取调用表达式的方法签名
        const methodSign = invokeExpr?.getMethodSignature();
        // 获取方法签名的子签名
        const subSignature = methodSign?.getMethodSubSignature();
        // 获取子签名的返回类型
        const returnType = subSignature?.getReturnType();
        // 获取返回类型的字符串表示
        const returnTypeString = returnType?.getTypeString();
        let text = stmt.getOriginalText() ?? '';
        this.asyncTextCheck1All(text, returnTypeString, method, asyncFunction, methodName, arkFile);
    }
    private asyncTextCheck1All(text: string, returnTypeString: string, method: ArkMethod, asyncFunction: string,
        methodName: string, arkFile: ArkFile): void {
        if (!this.containsAwaitKeyword(text)) {
            // 如果语句文本不包含catch、then、reject、resolve关键字
            if (!this.containsCatchKeyword(text) && !this.containsThenKeyword(text)) {
                this.asyncTextCheck1All1(returnTypeString, method, asyncFunction, text, methodName, arkFile);
            }
        }
    }
    private asyncTextCheck1All1(returnTypeString: string, method: ArkMethod, asyncFunction: string, text: string,
        methodName: string, arkFile: ArkFile): void {
        if (!this.containsRejectKeyword(text) && !this.containsResolveKeyword(text)) {
            this.asyncTextCheck1All12(returnTypeString, method, asyncFunction, text, methodName, arkFile);
        }
        if (!text.startsWith('await')) {
            this.asyncTextCheck1All12(returnTypeString, method, asyncFunction, text, methodName, arkFile);
        }
    }
    private asyncTextCheck1All12(returnTypeString: string, method: ArkMethod, asyncFunction: string, text: string,
        methodName: string, arkFile: ArkFile): void {
        if (this.containsPromiseKeyword(returnTypeString) || this.containsUnknownKeyword(returnTypeString) ||
            this.containsVoidKeyword(returnTypeString)) {
            this.asyncTextCheck1All11(text, method, asyncFunction, methodName, arkFile);
        }
    }
    private asyncTextCheck1All11(text: string, method: ArkMethod, asyncFunction: string,
        methodName: string, arkFile: ArkFile): void {
        if (!text.includes('return ') || text.includes('await ')) {
            const stmts = method.getBody()?.getCfg().getStmts() ?? [];
            let flag = { value: true };
            this.asyncTextCheck11(stmts, flag);
            this.asyncTextCheck12(flag, method);
            if (flag.value === true) {
                if (asyncFunction.includes('=>')) {
                    this.metaData.description = `Async arrow function has no 'await' expression.`;
                } else {
                    this.metaData.description = `Async function ${methodName} has no 'await' expression.`;
                }
                this.addIssueReport(arkFile, asyncFunction, this.metaData);
            }
        }
    }
    private asyncTextCheck11(stmts: Stmt[], flag: { value: boolean }): void {
        for (const stmt of stmts) {
            const text = stmt.getOriginalText() ?? '';
            if (this.containsAwaitKeyword(text)) {
                flag.value = false;
            }
        }
    }
    private asyncTextCheck12(flag: { value: boolean }, method: ArkMethod): void {
        const usedGlobals = method.getBody()?.getUsedGlobals() ?? [];
        for (const [key, value] of usedGlobals?.entries()) {
            const Value = value as unknown as valueType;
            const usedStmts = Value?.usedStmts ?? [];
            for (const usedStmt of usedStmts) {
                if (usedStmt instanceof ArkAssignStmt) {
                    const rightOp = usedStmt.getRightOp() as unknown as RightOp;
                    const methodName = rightOp?.yieldValue?.getMethodSignature()?.getMethodSubSignature()?.getMethodName() ?? '';
                    if (methodName !== '') {
                        flag.value = false;
                    }
                }
            }
        }
    }
    private asyncTextCheck2(asyncText: string, invokeExpr: AbstractInvokeExpr,
        stmt: Stmt, arkFile: ArkFile, method: ArkMethod): void {
        const methodName = method.getSignature()?.getMethodSubSignature()?.getMethodName() ?? '';
        if (methodName.includes('build')) {
            const regex = /=>/;
            const match = asyncText.match(regex);
            if (match) {
                this.asyncTextCheck2All(match, invokeExpr, stmt, arkFile);
            }
        }
    }
    private asyncTextCheck2All(match: RegExpMatchArray, invokeExpr: AbstractInvokeExpr,
        stmt: Stmt, arkFile: ArkFile): void {
        const asyncFunction = match[0];
        // 获取调用表达式的方法签名
        const methodSign = invokeExpr?.getMethodSignature();
        // 获取方法签名的子签名
        const subSignature = methodSign?.getMethodSubSignature();
        // 获取子签名的返回类型
        const returnType = subSignature?.getReturnType();
        // 获取返回类型的字符串表示
        const returnTypeString = returnType?.getTypeString();
        let text = stmt.getOriginalText() ?? '';
        this.asyncTextCheck2All1(text, arkFile, returnTypeString, asyncFunction);
    }
    private asyncTextCheck2All1(text: string, arkFile: ArkFile, returnTypeString: string,
        asyncFunction: string): void {
        if (!this.containsAwaitKeyword(text) && !this.containsCatchKeyword(text) && !this.containsThenKeyword(text) && !
            this.containsRejectKeyword(text)) {
            this.asyncTextCheck2All2(text, arkFile, returnTypeString, asyncFunction);
        }
    }
    private asyncTextCheck2All2(text: string, arkFile: ArkFile, returnTypeString: string,
        asyncFunction: string): void {
        if (this.containsPromiseKeyword(returnTypeString) || this.containsUnknownKeyword(returnTypeString) ||
            this.containsVoidKeyword(returnTypeString)) {
            this.asyncTextCheck2All11(text, arkFile, asyncFunction);
        }
    }
    private asyncTextCheck2All11(text: string, arkFile: ArkFile, asyncFunction: string): void {
        if (!text.includes('return ') || text.includes('await ')) {
            this.metaData.description = "Async arrow function has no 'await' expression.";
            this.addIssueReport(arkFile, asyncFunction, this.metaData);
        }
    }
    private addIssueReport(arkFile: ArkFile, name: string, metaData: BaseMetaData): void {
        const severity = this.rule.alert ?? metaData.severity;
        const warnInfo = this.getLineAndColumn(arkFile, name);
        this.metaData.description = metaData.description.padEnd(130);
        const filePath = arkFile.getFilePath();
        if (warnInfo) {
            let defects = new Defects(warnInfo.line, warnInfo.startCol, warnInfo.endCol, metaData.description, severity, this.rule.ruleId, filePath,
                metaData.ruleDocPath, true, false, false);
            this.issues.push(new IssueReport(defects, undefined));
            RuleListUtil.push(defects);
        }
    }
    private getLineAndColumn(arkFile: ArkFile, name: string): lineColumnInfo | null {
        if (!arkFile) {
            return null;
        }
        const code = arkFile.getCode() ?? '';
        const lines = code.split('\r\n');
        let lineNumber = 1;
        return this.getLineAndColumn1(name, lines, lineNumber, arkFile);
    }
    private getLineAndColumn1(name: string, lines: string[], lineNumber: number, arkFile: ArkFile): lineColumnInfo | null {
        for (const line of lines) {
            const lineIndex = line.indexOf(name);
            if (lineIndex !== -1) {
                return this.getLineAndColumn11(name, line, lineNumber, arkFile, lineIndex);
            }
            lineNumber++;
        }
        return null;
    }
    private getLineAndColumn11(name: string, line: string, lineNumber: number, arkFile: ArkFile, lineIndex: number): lineColumnInfo | null {
        if (name.includes('=>')) {
            const arrowIndex = line.indexOf('=>');
            return {
                line: lineNumber,
                startCol: arrowIndex + 1,
                endCol: arrowIndex + 1,
                filePath: arkFile.getFilePath()
            };
        } else {
            return {
                line: lineNumber,
                startCol: lineIndex + 1,
                endCol: lineIndex + 1,
                filePath: arkFile.getFilePath()
            };
        }
    }
}